package com.fuyun.rpc.client.annotations;

import com.fuyun.rpc.client.config.RpcApplication;
import com.fuyun.rpc.client.proxy.ServiceProxyFactory;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

import java.lang.reflect.Field;

/**
 * RpcConsumerBootstrap类负责为标记了FuyunRpcAutowired注解的字段注入远程服务代理对象 它实现了BeanPostProcessor接口，以在Spring框架的Bean初始化后进行处理
 *
 * @author: zrq1351
 * @date: 2025/2/20
 */
@Slf4j
public class RpcConsumerBootstrap implements BeanPostProcessor {

	private final RpcApplication rpcApplication;

	public RpcConsumerBootstrap(RpcApplication rpcApplication) {
		this.rpcApplication = rpcApplication;
	}

	/**
	 * 在Bean初始化后进行处理，主要用于为标记了FuyunRpcAutowired注解的字段注入远程服务代理对象
	 *
	 * @param bean     初始化后的Bean对象
	 * @param beanName Bean名称
	 * @return 处理后的Bean对象
	 * @throws BeansException 如果处理过程中发生异常
	 */
	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		Class<?> beanClass = bean.getClass();
		// 遍历对象的所有属性
		Field[] declaredFields = beanClass.getDeclaredFields();
		for (Field field : declaredFields) {
			FuyunRpcAutowired rpcReference = field.getAnnotation(FuyunRpcAutowired.class);
			if (rpcReference != null) {
				// 为属性生成代理对象
				Class<?> interfaceClass = rpcReference.serviceClass();
				if (interfaceClass == void.class) {
					interfaceClass = field.getType();
				}
				RpcApplication rpc = rpcApplication.deepCopy();
				getRpcApplication(rpc, rpcReference);
				field.setAccessible(true);
				Object proxyObject = ServiceProxyFactory.getProxy(interfaceClass, rpc);
				try {
					field.set(bean, proxyObject);
					field.setAccessible(false);
				} catch (IllegalAccessException e) {
					throw new RuntimeException("为字段注入代理对象失败", e);
				}
			}
		}
		return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
	}

	/**
	 * 根据FuyunRpcAutowired注解的属性值更新RpcApplication配置对象
	 *
	 * @param rpcApplication Rpc应用配置对象，用于创建远程服务代理对象
	 * @param rpcReference   FuyunRpcAutowired注解对象，包含远程服务调用的配置信息
	 */
	private void getRpcApplication(RpcApplication rpcApplication, FuyunRpcAutowired rpcReference) {
		rpcApplication.getRpcConfig().setLoadBalancer(
			StringUtils.defaultIfEmpty(rpcReference.loadBalancer(), rpcApplication.getRpcConfig().getLoadBalancer()));
		rpcApplication.getRpcConfig().setRetryStrategy(
			StringUtils.defaultIfEmpty(rpcReference.retryStrategy(), rpcApplication.getRpcConfig().getRetryStrategy()));
		rpcApplication.getRpcConfig().setTolerantStrategy(StringUtils.defaultIfEmpty(rpcReference.tolerantStrategy(),
			rpcApplication.getRpcConfig().getTolerantStrategy()));
		rpcApplication.getRpcConfig().setMock(rpcReference.mock());

		rpcApplication.getRegistryConfig().setServiceVersion(StringUtils.defaultIfEmpty(rpcReference.serviceVersion(),
			rpcApplication.getRegistryConfig().getServiceVersion()));
		rpcApplication.getRegistryConfig().setGroup(
			StringUtils.defaultIfEmpty(rpcReference.serviceGroup(), rpcApplication.getRegistryConfig().getGroup()));
	}

}